#include <jni.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <syslog.h>
#include "isccn_pdt_header.h"

extern "C" {
#include "isccn_pdt_header.h"
}

extern "C"
jstring
Java_com_vanzo_encryption_Pdt_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    isccn_pdt_get_killstatus();
    return env->NewStringUTF(hello.c_str());
}
//jni test
extern "C"
jint Java_com_vanzo_encryption_Pdt_test(
        JNIEnv *env,jobject thiz,
        jint a,jint b){
    return a+b;
}


//int isccn_pdt_system_command(IN unsigned char *inValue,IN int iLen,OUT unsigned char *outValue,OUT int* oLen);
extern "C"
jint Java_com_vanzo_encryption_Pdt_systemCommand(
        JNIEnv *env, jobject thiz,
        jbyteArray inValue, jbyteArray outValue, jobject outLen) {
//    syslog(LOG_ERR, " billy  :%d", 12);
    void *in = env->GetByteArrayElements(inValue, NULL);
    int iLen = env->GetArrayLength(inValue);
    unsigned char out[4096];
    int oLen = 0;
    int ret = isccn_pdt_system_command((unsigned char *) in, iLen, out, &oLen);

    if (ret >= 0 && oLen > 0) {
        env->SetByteArrayRegion(outValue, 0, oLen, (jbyte *) out);
        jclass clazz = env->GetObjectClass(outLen);
        jfieldID fi = env->GetFieldID(clazz, "value", "I");
        env->SetIntField(outLen, fi, oLen);
    }
    env->ReleaseByteArrayElements(inValue, (jbyte *) in, JNI_ABORT);
//    if (out != NULL)
//        env->ReleaseByteArrayElements(outValue, (jbyte*)out, JNI_ABORT);
//    syslog(LOG_ERR, " billy  :%d", ret);
    return ret;
}


//当前组号，当前终端号,组内所有终端数,iLen调用开始时为value缓存长度，调用完成后为value内容长度
//int isccn_android_pdt_get_group(IN int groupId,IN int terminalId,IN int totalTerminalSize,OUT unsigned char *value,IN int* iLen);
extern "C"
jint Java_com_vanzo_encryption_Pdt_getKillKey(
        JNIEnv *env, jobject thiz,
        jbyteArray gk, jobject iLen) {
    jclass clazz = env->GetObjectClass(iLen);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    int len = env->GetIntField(iLen, fi);
    unsigned char oValue[4096];
    int ret = isccn_android_pdt_get_killkey((unsigned char *) oValue, len);
    if (ret >= 0 && len > 0) {
        env->SetByteArrayRegion(gk, 0, len, (jbyte *) oValue);
        env->SetIntField(iLen, fi, len);
    }
//    syslog(LOG_ERR, " billy ret :%d", ret);
//    syslog(LOG_ERR, " billy o :%d", ret);
    return ret;
}

//当前组号，当前终端号,组内所有终端数,iLen调用开始时为value缓存长度，调用完成后为value内容长度
//int isccn_android_pdt_get_group(IN int groupId,IN int terminalId,IN int totalTerminalSize,OUT unsigned char *value,IN int* iLen);
extern "C"
jint Java_com_vanzo_encryption_Pdt_getGroupKey(
        JNIEnv *env, jobject thiz,
        jbyteArray gk, jobject iLen) {
    jclass clazz = env->GetObjectClass(iLen);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    int len = env->GetIntField(iLen, fi);
    unsigned char oValue[4096];
    int ret = isccn_android_pdt_get_groupkey((unsigned char *) oValue, len);
    if (ret >= 0 && len > 0) {
        env->SetByteArrayRegion(gk, 0, len, (jbyte *) oValue);
        env->SetIntField(iLen, fi, len);
    }
//    syslog(LOG_ERR, " billy ret :%d", ret);
//    syslog(LOG_ERR, " billy o :%d", ret);
    return ret;
}

//当前组号，当前终端号,组内所有终端数,iLen调用开始时为value缓存长度，调用完成后为value内容长度
//int isccn_android_pdt_get_superkey2NFC(IN int groupId,IN int terminalId,IN int totalTerminalSize,OUT unsigned char *value,IN int* iLen);
extern "C"
jint Java_com_vanzo_encryption_Pdt_getSuperkey2NFC(
        JNIEnv *env, jobject thiz,
        jint groupId, jint terminalId, jint firstId,jint totalTerminalSize,
        jint channelId, jint isChannelLock,
        jbyteArray gk,
        jbyteArray kk,
        jbyteArray value, jobject iLen) {
    jclass clazz = env->GetObjectClass(iLen);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    int len = env->GetIntField(iLen, fi);
    unsigned char oValue[4096];

//    syslog(LOG_ERR, " billy groupId:%d", groupId);
    int ret = isccn_android_pdt_get_superkey2NFC(groupId, terminalId, firstId, totalTerminalSize,
                                                 channelId, isChannelLock,
                                                 (unsigned char *) gk, (unsigned char *) kk,
                                                 (unsigned char *) oValue, &len);

    if (ret >= 0 && len > 0) {
        env->SetByteArrayRegion(value, 0, len, (jbyte *) oValue);
        env->SetIntField(iLen, fi, len);
    }
    return ret;
}

//Android侧收到NFC数据后进行解析
//groupId,terminalId通过AT指令给模块,totalTerminalSize为组内所有成员数量,ioLen调用开始时为out_value缓存长度，调用完成后为out_value内容长度
//out_value通过AT+Binary指令给模块
//int isccn_android_pdt_parse_superkeyFromNFC(IN unsigned char *in_value, IN int iLen, IN
//                                            int *groupId, IN
//                                            int *terminalId, IN int *totalTerminalSize, OUT
//                                            unsigned char *out_value, IN OUT int *ioLen);

extern "C"
jint Java_com_vanzo_encryption_Pdt_parseSuperkeyFromNFC(
        JNIEnv *env, jobject thiz,
        jbyteArray in_value, jobject iiLen, jobject groupId, jobject terminalId,
        jobject totalTerminalSize, jobject firstId,
        jobject channelId, jobject isChannelLock,
        jbyteArray out_value, jobject ioLen) {
    void *inValue = env->GetByteArrayElements(in_value, NULL);
    jclass clazz = env->GetObjectClass(groupId);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    int gid = env->GetIntField(groupId, fi);
    int tid = env->GetIntField(terminalId, fi);
    int tsize = env->GetIntField(totalTerminalSize, fi);
    int tfid = env->GetIntField(firstId, fi);
    int iLid = env->GetIntField(iiLen, fi);
    int chid = env->GetIntField(channelId, fi);
    int chlock = env->GetIntField(isChannelLock, fi);
    unsigned char oValue[4096];
    int iolen = env->GetIntField(ioLen, fi);
//    syslog(LOG_ERR, " billy ilen:%d", iLid);
    int ret = isccn_android_pdt_parse_superkeyFromNFC((unsigned char *) inValue, iLid, &gid, &tid,
                                                      &tsize,
                                                      &tfid,
                                                      &chid, &chlock,
                                                      (unsigned char *) oValue, &iolen);
    if (ret >= 0 && iolen > 0) {
        env->SetByteArrayRegion(out_value, 0, iolen, (jbyte *) oValue);
        env->SetIntField(ioLen, fi, iolen);
        env->SetIntField(groupId, fi, gid);
        env->SetIntField(terminalId, fi, tid);
        env->SetIntField(totalTerminalSize, fi, tsize);
        env->SetIntField(firstId, fi, tfid);
        env->SetIntField(channelId, fi, chid);
        env->SetIntField(isChannelLock, fi, chlock);
    }
    return ret;
}


//获取机器状态

extern "C"
jint Java_com_vanzo_encryption_Pdt_getDeviceStatus(
        JNIEnv *env, jobject thiz,
        jbyteArray value,
        jobject length) {
    jclass clazz = env->GetObjectClass(length);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    int len = env->GetIntField(length, fi);
    unsigned char oValue[4096];

//    syslog(LOG_ERR, " billy groupId:%d", groupId);
    int ret = isccn_android_pdt_generate_uartcmd((unsigned char) TYPE_DEVICE_STATUS,
                                                 (unsigned char *) oValue, &len);

    if (ret >= 0 && len > 0) {
        env->SetByteArrayRegion(value, 0, len, (jbyte *) oValue);
        env->SetIntField(length, fi, len);
    }
    return ret;
}

//获取上一次操作结果
extern "C"
jint Java_com_vanzo_encryption_Pdt_getLastCmdResult(
        JNIEnv *env, jobject thiz,
        jbyteArray value,
        jobject length) {
    jclass clazz = env->GetObjectClass(length);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    int len = env->GetIntField(length, fi);
    unsigned char oValue[4096];

//    syslog(LOG_ERR, " billy groupId:%d", groupId);
    int ret = isccn_android_pdt_generate_uartcmd((unsigned char) TYPE_DEVICE_LAST_CMD_RESULT,
                                                 (unsigned char *) oValue, &len);

    if (ret >= 0 && len > 0) {
        env->SetByteArrayRegion(value, 0, len, (jbyte *) oValue);
        env->SetIntField(length, fi, len);
    }
    return ret;
}

extern "C"
jint Java_com_vanzo_encryption_Pdt_sendKillMessage(
        JNIEnv *env, jobject thiz,
        jint groupId, jint terminalId,
        jbyteArray kk,
        jbyteArray value, jobject iLen) {
    jclass clazz = env->GetObjectClass(iLen);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    int len = env->GetIntField(iLen, fi);
    unsigned char oValue[4096];

//    syslog(LOG_ERR, " billy groupId:%d", groupId);
    int ret = isccn_android_pdt_send_killmessage(groupId, terminalId, (unsigned char *) kk,
                                                 (unsigned char *) oValue, &len);

    if (ret >= 0 && len > 0) {
        env->SetByteArrayRegion(value, 0, len, (jbyte *) oValue);
        env->SetIntField(iLen, fi, len);
    }
    return ret;
}

extern "C"
jint Java_com_vanzo_encryption_Pdt_sendMessage(
        JNIEnv *env, jobject thiz,
        jint groupId, jint terminalId,
        jbyteArray msg,
        jbyteArray value, jobject iLen) {
    jclass clazz = env->GetObjectClass(iLen);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    int len = env->GetIntField(iLen, fi);
    unsigned char oValue[4096];

//    syslog(LOG_ERR, " billy groupId:%d", groupId);
    int ret = isccn_android_pdt_send_message(groupId, terminalId, (unsigned char *) msg,
                                             (unsigned char *) oValue, &len);

    if (ret >= 0 && len > 0) {
        env->SetByteArrayRegion(value, 0, len,(jbyte *) oValue);
        env->SetIntField(iLen, fi, len);
    }
    return ret;
}

extern "C"
jint Java_com_vanzo_encryption_Pdt_parseBinary(
        JNIEnv *env, jobject thiz,
        jbyteArray binary, jint binaryLength,
        jbyteArray type, jobject length,
        jbyteArray value) {
    jclass clazz = env->GetObjectClass(length);
    jfieldID fi = env->GetFieldID(clazz, "value", "I");
    short len = env->GetShortField(length, fi);
    unsigned char *oValue;
    unsigned char oType[4096];

//    syslog(LOG_ERR, " billy groupId:%d", groupId);
    int ret = isccn_android_pdt_parse_uart_return((unsigned char *) binary, binaryLength,
                                                  (unsigned char *) oType, (unsigned short *) &len,
                                                  &oValue);

    if (ret >= 0 && len > 0) {
		env->SetByteArrayRegion(type, 0, len, (jbyte *)oType);
        if ( oType[0] == TYPE_DEVICE_LAST_CMD_RESULT )
		{
			env->SetByteArrayRegion(value,0,1, (jbyte *)oValue);
			env->SetShortField(length,fi,1);
		}
		else if ( oType[0] == TYPE_DEVICE_STATUS )
		{
			android_pdt_devicestatus* ptstatus = (android_pdt_devicestatus*)oValue;
            env->SetByteArrayRegion(value,0,1, (jbyte *)&ptstatus->device_keyupdated);//第一个字节1-更新成功，0-未成功
            env->SetByteArrayRegion(value,1,2, (jbyte *)&ptstatus->device_killed);//第二个字节1,被遥毙,0--未遥毙
			env->SetShortField(length,fi,2);
		}
		else
		{
			env->SetShortField(length,fi,0);
		}
    }
    return ret;
}
